/**
 * GPIO 驱动的 n 位开关
 * @detail GPIO 驱动的 n 位开关由 n 个 GPIO 引脚驱动，有两种典型应用场景:
 *  - 做为 1xN (单刀 N 置)的开关驱动编码器使用: 这时 N 个 GPIO 引脚构成一个 N 位 port 编码，代表开关要切换到 0 ~ (2^n - 1) 之间的某个位置 
 *  - 做为 N 个独立开关的数组使用: 这时 N 个 GPIO 引脚构成一个 N 位 mask 状态码，每一位代表一个开关的状态(ON 或 OFF)
 * @author 张勇 / 2020-05-13
 */

#pragma once

#include "mcu.h"

#ifdef __cplusplus
extern "C" {
#endif

/// @brief 声明命名的 GPIO 驱动的 n 位开关 API 接口
typedef std_err_t (*func_switchxn_switch)(size_t port_mask);
typedef std_err_t (*func_switchxn_state)(uint32_t *port_mask);

/**
 * 直接使用 GPIO 引脚号的开关
 *
 * 应用示例:
 *   // 使用 GPIO 引脚号定义开关
 *   SWITCHXN_DEFINE(RXCH_4P4T_14, 2, 0) = {MCU_GPIO_NUM_PB3, MCU_GPIO_NUM_PB2}; // PCB 信号名: RX1_4_IN_SWV1C, RX1_4_IN_SWV2C
 *   
 *   // 使用命名的开关接口
 *   RXCH_4P4T_14_Init(0);
 *   RXCH_4P4T_14_Switch(2);
 *   int currport = RXCH_4P4T_14_CurrPort();
 */
 
/// @brief 开关初始化: 初始化所有引脚为输出，并设置开关初始位置
/// @param n 有多少个开关，n <= 32
/// @param pins 开关 GPIO 引脚数组，数量为 n
/// @param out_mode GPIO 引脚输出模式
/// @param active_level 开关引脚编码为 1 时的 GPIO 电平
/// @param port_mask 开关初始状态: 做为单刀 N 置的开关驱动时表示要切换到的介于 0 ~ (2^n - 1) 之间的 port；做为 N 个独立开关的驱动时表示开关 mask 状态码。
/// @return 标准错误码
std_err_t unidrv_switchxn_init(uint8_t n, mcu_gpio_num_t *pins, mcu_gpio_mode_t out_mode, bool active_level, uint32_t port_mask);

/// @brief 开关切换
std_err_t unidrv_switchxn_switch(uint8_t n, mcu_gpio_num_t *pins, bool active_level, uint32_t port_mask);

/// @brief 开关当前状态
std_err_t unidrv_switchxn_state(uint8_t n, mcu_gpio_num_t *pins, bool active_level, uint32_t *port_mask);

/// @brief 声明命名的 GPIO 驱动的 n 位开关
#define SWITCHXN_DECLARE(NAME) \
	std_err_t NAME##_Init(uint32_t port_mask);   \
	std_err_t NAME##_Switch(uint32_t port_mask); \
	std_err_t NAME##_State(uint32_t *port_mask);

/// @brief 定义命名的 GPIO 驱动的 n 位开关
#define SWITCHXN_DEFINE(NAME, N, OUTMODE, ACTIVE_LEVEL) \
	extern mcu_gpio_num_t _##NAME##_PINS[N]; \
	std_err_t NAME##_Init(uint32_t port_mask)   { return unidrv_switchxn_init(N, _##NAME##_PINS, MCU_GPIO_MODE_##OUTMODE, ACTIVE_LEVEL, port_mask); } \
	std_err_t NAME##_Switch(uint32_t port_mask) { return unidrv_switchxn_switch(N, _##NAME##_PINS, ACTIVE_LEVEL, port_mask); }                        \
	std_err_t NAME##_State(uint32_t *port_mask) { return unidrv_switchxn_state(N, _##NAME##_PINS, ACTIVE_LEVEL, port_mask); }                               \
	mcu_gpio_num_t _##NAME##_PINS[N]
	

/**
 * 使用 I/O 函数驱动的开关: 可用于更高级别的抽象
 *
 * 应用示例:
 *   // 先定义 GPIO 引脚以取得 GPIO 引脚控制函数
 *   GPIO_DEFINE_POLARITY(RXCH_4P4T_14_P1, PB3 , 1); // PCB 信号名: RX1_4_IN_SWV1C
 *   GPIO_DEFINE_POLARITY(RXCH_4P4T_14_P2, PB2 , 1); // PCB 信号名: RX1_4_IN_SWV2C
 *
 *   // 使用 GPIO 引脚控制函数初始化开关
 *   SWITCHXN_DEFINE(RXCH_4P4T_14, 2) = {
 *       {GPIO_RXCH_4P4T_14_P1_Switch , GPIO_RXCH_4P4T_14_P2_Switch },
 *       {GPIO_RXCH_4P4T_14_P1_IsOutOn, GPIO_RXCH_4P4T_14_P2_IsOutOn}
 *   };
 *   
 *   // 使用命名的开关接口
 *   RXCH_4P4T_14_Switch(2);
 *   int currport = RXCH_4P4T_14_CurrPort();
 */
 
std_err_t unidrv_switchxnf_switch(uint8_t n, func_gpio_switch_t *set, uint32_t port_mask);
std_err_t unidrv_switchxnf_state(uint8_t n, func_gpio_is_out_on_t *get, uint32_t *port_mask);

#define SWITCHXNF_DEFINE(NAME, N)           \
	typedef struct {                       \
		func_gpio_switch_t    set[N];      \
		func_gpio_is_out_on_t get[N];      \
	} NAME##_t;                            \
	extern NAME##_t NAME;                  \
	std_err_t NAME##_Switch(uint32_t port_mask) { return unidrv_switchxnf_switch(N, NAME.set, port_mask); } \
	std_err_t NAME##_State(uint32_t *port_mask) { return unidrv_switchxnf_state(N, NAME.get, port_mask); }  \
	NAME##_t NAME
	
#ifdef __cplusplus
}
#endif
